package lottery

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"sync"
	"time"

	"lottery/conf"
	"lottery/constant"
	"lottery/libs/mq"
	"lottery/models"
	"lottery/utils"

	"code.google.com/p/go.net/context"
	"github.com/astaxie/beego/logs"
)

type LotteryCell struct {
	Lottery   ILottery // 账号
	Prepare   bool     // 是否准备下单
	InUse     bool
	timestamp int64 // 毫秒
}

func (l *LotteryCell) Active() {
	l.InUse = true
}

func (l *LotteryCell) Sleep() {
	l.timestamp = utils.CurrentMills()
	l.Prepare = false
	l.InUse = false
}

func (l *LotteryCell) InSleep() bool {
	currentMill := utils.CurrentMills()
	switch l.Lottery.Platform() {
	case constant.ISN99:
		// isn 休眠200ms
		return currentMill-l.timestamp < 200
	case constant.U16888:
		return false
		// 利记 休 眠50ms

		return currentMill-l.timestamp < 50
	case constant.PS3838:
		return currentMill-l.timestamp < 1000
	default:
		return false
	}
}

// 用户处理器
// 每个用户的设置程序将在这里处理
type UserProc struct {
	had              int32
	user             *models.User
	mux              *sync.RWMutex
	followLimit      int                            // 关注水位
	policys          []*models.Policy               // 策略
	gameIdCache      map[string]int64               // 比赛ID缓存
	gameCache        map[string]*models.Game        // 比赛ID缓存
	gameDatasCache   map[int][]*models.GameData     // 比赛数据Cache 做策略时注意过期数据
	handicapTypeMap  map[int]bool                   // 盘口类型限制
	gameDatasChan    chan []*models.GameData        // 比赛数据输入
	tickCellChan     chan []*PlayCell               // 点水队列
	playCellChan     chan []*PlayCell               // 下注队列
	orderChan        chan *models.Order             // 订单信息获取
	u16888HandicapId Cache                          // 利记盘口 // 账号ID_gameId_handicapType_abs(handicap) => handicapId
	cache            Cache                          // 如果已经下过单的盘口不再下注
	lotterys         map[int]map[int64]*LotteryCell // 水位获取账号
	gameDataTopic    string
	resCfg           conf.ResourceConfig
	mq               mq.MessageQueue
}

func NewUserProc(user *models.User) *UserProc {
	res := conf.LoadResource()
	kafkaMq, err := mq.OpenBaseKafkaMQ()
	if err != nil {
		panic(err)
	}

	return &UserProc{
		user:             user,
		mux:              new(sync.RWMutex),
		followLimit:      12,
		gameCache:        make(map[string]*models.Game),
		gameIdCache:      make(map[string]int64),
		gameDatasCache:   make(map[int][]*models.GameData),
		handicapTypeMap:  make(map[int]bool),
		gameDatasChan:    make(chan []*models.GameData, 1000),
		tickCellChan:     make(chan []*PlayCell, 100),
		playCellChan:     make(chan []*PlayCell, 100),
		orderChan:        make(chan *models.Order, 100),
		u16888HandicapId: NewRedisCache(),
		cache:            NewRedisCache(),
		lotterys:         make(map[int]map[int64]*LotteryCell),
		resCfg:           res,
		mq:               kafkaMq,
		gameDataTopic:    res.GameDataTopic,
	}
}

// 用户处理器自理
func (u *UserProc) Run() {
	// 限制条件加载
	u.loadHandicapType()
	go u.loadPolicys()
	go u.tickLoadAgents() // 定时加载设置的客户端
	u.Proc()
}

func (u *UserProc) loadHandicapType() {
	for _, handicapType := range u.resCfg.HandicapTypes {
		u.handicapTypeMap[handicapType] = true
	}
}

// 加载用户设置的策略
// 更新时应该使用消息队列通知
func (u *UserProc) loadPolicys() {
	tick := time.NewTicker(time.Second * 5)
	for _ = range tick.C {
		policys, err := models.LoadPolicyByUserId(u.user.Id)
		if err != nil {
			logs.Warn("loadPolicys %d %s", u.user.Id, err.Error())
			continue
		}

		u.mux.Lock()
		u.policys = policys
		u.mux.Unlock()
	}
}

func (u *UserProc) tickLoadAgents() {
	u.loadAgents()
	tick := time.NewTicker(time.Duration(3) * time.Second)
	for _ = range tick.C {
		u.loadAgents()
	}
}

func (u *UserProc) saveGameDatas2Mq(gameDatas []*models.GameData) (err error) {
	if len(gameDatas) == 0 {
		return
	}

	msg, err := json.Marshal(gameDatas)
	if err != nil {
		return
	}

	return u.mq.SendString(u.gameDataTopic, string(msg))
}

func (u *UserProc) setGameDatas(platformId int, gameDatas []*models.GameData) {
	u.mux.Lock()
	u.gameDatasCache[platformId] = gameDatas
	u.mux.Unlock()
}

// 不同球赛
func (u *UserProc) getRandomGameGameData(platformId int, gameId int64, handicapType int, handicap float64) (gameData *models.GameData) {
	u.mux.RLock()
	gameDatas, ok := u.gameDatasCache[platformId]
	u.mux.RUnlock()
	if !ok {
		return
	}

	for _, gameData := range gameDatas {
		if gameData.GameId != gameId {
			return gameData
		}
	}
	return
}

// 同球赛不同盘口类型
func (u *UserProc) getRandomHandicapGameData(platformId int, gameId int64, handicapType int, handicap float64) (gameData *models.GameData) {
	u.mux.RLock()
	gameDatas, ok := u.gameDatasCache[platformId]
	u.mux.RUnlock()
	if !ok {
		return
	}

	for _, gameData := range gameDatas {
		if gameData.GameId == gameId && gameData.HandicapType != handicapType {
			return gameData
		}
	}
	return
}

// 同球赛同盘口类型不同盘口
func (u *UserProc) getRandomGameData(platformId int, gameId int64, handicapType int, handicap float64) (gameData *models.GameData) {
	u.mux.RLock()
	gameDatas, ok := u.gameDatasCache[platformId]
	u.mux.RUnlock()
	if !ok {
		return
	}

	for _, gameData := range gameDatas {
		if gameData.GameId == gameId && gameData.HandicapType == handicapType && gameData.Handicap != handicap {
			return gameData
		}
	}
	return
}

func (u *UserProc) getGameData(platformId int, gameId int64, handicapType int, handicap float64) (gameData *models.GameData) {
	u.mux.RLock()
	gameDatas, ok := u.gameDatasCache[platformId]
	u.mux.RUnlock()
	if !ok {
		return
	}

	for _, gameData := range gameDatas {
		if gameData.GameId == gameId && gameData.HandicapType == handicapType && gameData.Handicap == handicap {
			return gameData
		}
	}
	return
}

func (u *UserProc) procTrigger(gameDatasChan <-chan []*models.GameData) {
	// 业务处理规则
	for gameDatas := range gameDatasChan {
		u.trigger(gameDatas)
	}
}

// 处理设置选项
func (u *UserProc) Proc() {
	gameDatasChan := make(chan []*models.GameData, 100)
	once := new(sync.Once)
	once.Do(func() {
		// 下单结果抓取
		go u.getOrderResult()
		go u.tickUpdateOrderResult()

		// 下注携程
		for i := 0; i < 100; i++ {
			go u.playProc()
		}

		// 点水携程
		go u.tickProc()

		// 数据处理携程
		for i := 0; i < 10; i++ {
			go u.procTrigger(gameDatasChan)
		}
	})

	gameDataMap := make(map[int][]*models.GameData)
	timeOut := 500 * time.Millisecond
	ctx, cancel := context.WithTimeout(context.Background(), timeOut)
	for {
		select {
		case tmpGameDatas := <-u.gameDatasChan:
			if len(tmpGameDatas) < 1 {
				continue
			}

			gameDataMap[tmpGameDatas[0].PlatformId] = tmpGameDatas
		case <-ctx.Done():
			for platformId, gameDatas := range gameDataMap {
				if len(gameDatas) > 0 {
					logs.Debug("处理平台%d列表数据共%d", platformId, len(gameDatas))
					u.setGameDatas(platformId, gameDatas)
					gameDatasChan <- gameDatas
				}
			}
			cancel()
			ctx, cancel = context.WithTimeout(context.Background(), timeOut)
		}
	}
}

// 定时更新下单结果
func (u *UserProc) tickUpdateOrderResult() {
	// 抓取5分钟内的订单
	upTime := time.Minute * 5
	tick := time.NewTicker(time.Second * 30)
	for _ = range tick.C {
		orders, err := models.GetOrderList4UpResult(u.user.Id, upTime)
		if err != nil {
			continue
		}

		for _, order := range orders {
			u.orderChan <- order
		}
	}
}

func (u *UserProc) getOrderResult() {
	for order := range u.orderChan {
		logs.Notice("开始抓取 orderid = %d下注记录,平台1下单状态:%d,平台2下单状态:%d", order.Id, order.Platform1Status, order.Platform2Status)
		logs.Notice("订单信息:账号1Id%d,账号2Id%d", order.Platform1AgentId, order.Platform2AgentId)
		go func() {
			u.getOrderResultInfo(order)
		}()
	}
}

//用携程跑每一个订单信息
func (u *UserProc) getOrderResultInfo(order *models.Order) {
	time.Sleep(20 * time.Second)

	for i := 0; i < 5; i++ {
		// 下注成功
		time.Sleep(5 * time.Second)
		result := false
		if order.Platform1Status == 1 {
			logs.Notice("order:%d platformId:%d 开始爬取下注记录", order.Id, order.Platform1Id)
			lottery, ok := u.getLottery(order.Platform1AgentId, order.Platform1Id)
			logs.Notice("order:%d platformId:%d 获取lottery状态%t", order.Id, order.Platform1Id, ok)
			if ok {
				//logs.Notice("order:%d 信息,platformId :%d", order.Id, order.Platform1Id)
				html, err := lottery.GetOrderInfo(time.Now())
				if err != nil {
					logs.Notice("order:%d platformId:%d抓取html失败,err:%s", order.Id, order.Platform1Id, err.Error())
					continue
				}

				if err := order.UpdatePlatform1Result(html); err != nil {
					logs.Notice("order:%d platformId:%d 保存html到数据库失败 err:%s", order.Id, order.Platform1Id, order.Platform1AgentId, err.Error())
				} else {
					logs.Notice("order:%d platformId:%d 保存html到数据库成功", order.Id, order.Platform2Id)
					result = true
				}
			} else {
				logs.Notice("order:%d platformId:%d 获取lottery失败 platformId:%d agentId:%d", order.Platform1Id, order.Platform1Id, order.Platform1AgentId)
			}

			if result {
				break
			}
			if !result && i == 4 {
				logs.Notice("Order:%d platformId:%d 抓取下单记录重试5次失败了!", order.Id, order.Platform1Id)
			}
		} else {
			logs.Notice("order:%d Platform:%d Status:%d爬取失败 原因:下单结果不等于1 Platform:%d Status:%d", order.Id, order.Platform1Id, order.Platform1Status)
		}

	}

	// 下注成功
	for i := 0; i < 5; i++ {
		time.Sleep(5 * time.Second)
		result := false
		if order.Platform2Status == 1 {
			logs.Notice("order:%d platformId:%d 开始爬取下注记录", order.Id, order.Platform2Id)
			lottery, ok := u.getLottery(order.Platform2AgentId, order.Platform2Id)
			logs.Notice("order:%d platformId:%d 获取lottery状态%t", order.Id, order.Platform2Id, ok)
			if ok {
				//logs.Notice("开始抓取 order:%d 信息,platformId :%d", order.Id, order.Platform2Id)
				html, err := lottery.GetOrderInfo(time.Now())
				if err != nil {
					logs.Notice("order:%d platformId:%d抓取html失败,err:%s", order.Id, order.Platform2Id, err.Error())
					continue
				}

				if err := order.UpdatePlatform2Result(html); err != nil {
					logs.Notice("order:%d platformId:%d 保存html到数据库失败 err:%s", order.Id, order.Platform2Id, order.Platform2AgentId, err.Error())
				} else {
					logs.Notice("order:%d platformId:%d 保存html到数据库成功", order.Id, order.Platform2Id)
					result = true
				}
			} else {
				logs.Notice("order:%d platformId:%d 获取lottery失败 platformId:%d agentId:%d", order.Platform2Id, order.Platform2Id, order.Platform2AgentId)
				//logs.Warn("获取下单结果失败,找不到账号 platformId:%d agentId:%d", order.Platform1Id, order.Platform1AgentId)
			}
			if result {
				break
			}
			if !result && i >= 4 {
				logs.Notice("Order:%d platformId:%d 抓取下单记录重试5次失败了!", order.Id, order.Platform2Id)
			}
		} else {
			logs.Notice("order:%d Platform:%d Status:%d爬取失败 原因:下单结果不等于1 Platform:%d Status:%d", order.Id, order.Platform2Id, order.Platform2Status)
		}

	}

}

func (u *UserProc) setU16888HandicapId(agent *models.Agent, gameData *models.GameData) {
	if agent.PlatformId != constant.U16888 {
		return
	}

	u.u16888HandicapId.SetExp(u.getU16888HandicapIdKey(agent, gameData), gameData.HandicapId, time.Minute*90)
}

func (u *UserProc) getU16888HandicapIdKey(agent *models.Agent, gameData *models.GameData) string {
	return fmt.Sprintf("%d_%d_%d_%0.2f", agent.Id, gameData.GameId, gameData.HandicapType, gameData.Handicap)
}

func (u *UserProc) fillU16888HandicapId(agent *models.Agent, gameData *models.GameData) (ok bool) {
	if agent.PlatformId != constant.U16888 {
		return
	}

	var err error
	gameData.HandicapId, err = u.u16888HandicapId.Get(u.getU16888HandicapIdKey(agent, gameData))
	if err == nil {
		ok = true
	}
	return
}

func (u *UserProc) saveGameDatas(gameDatas []*models.GameData, agent *models.Agent) (err error) {
	for _, gameData := range gameDatas {
		gameData.UserId = u.user.Id
		gameData.PlatformId = agent.PlatformId
		if !u.FillGame(gameData) {
			gameData.FillGame()
		}

		if agent.PlatformId == constant.U16888 {
			u.setU16888HandicapId(agent, gameData)
		}
	}

	if err := u.saveGameDatas2Mq(gameDatas); err != nil {
		logs.Warn("入队列失败 %s", err.Error())
	}

	start := utils.CurrentMills()
	u.gameDatasChan <- gameDatas
	logs.Debug("入队列耗时:%d ms", utils.CurrentMills()-start)
	return
}

func (u *UserProc) gameKey(platformId int, platformGameId string) string {
	return fmt.Sprintf("%d_%s", platformId, platformGameId)
}

func (u *UserProc) getGame(platformId int, platformGameId string) (game *models.Game, ok bool) {
	u.mux.RLock()
	game, ok = u.gameCache[u.gameKey(platformId, platformGameId)]
	u.mux.RUnlock()
	return
}

func (u *UserProc) FillGame(gameData *models.GameData) (ok bool) {
	u.mux.RLock()
	gameData.GameId, ok = u.gameIdCache[u.gameKey(gameData.PlatformId, gameData.PlatformGameId)]
	gameData.Game, ok = u.gameCache[u.gameKey(gameData.PlatformId, gameData.PlatformGameId)]
	u.mux.RUnlock()
	return
}

// 保存赛事信息
func (u *UserProc) saveGames(games []*models.Game, agent *models.Agent) error {
	for _, game := range games {
		game.UserId = u.user.Id
		game.PlatformId = agent.PlatformId
		var ok bool
		var key string = u.gameKey(agent.PlatformId, game.PlatformGameId)

		u.mux.RLock()
		game.Id, ok = u.gameIdCache[key]
		u.mux.RUnlock()
		if !ok {
			u.mux.Lock()
			if e := models.UpsertGame(game); e != nil {
				u.mux.Unlock()
				continue
			}

			u.gameCache[key] = game
			u.gameIdCache[key] = game.Id
			u.mux.Unlock()
		}
	}
	return nil
}

func (u *UserProc) loadAgents() {
	agents := u.getAgents()
	for _, agent := range agents {
		// 基础账号类型
		if agent.Alive() {
			if u.existsAgent(agent) {
				continue
			}
			logs.Notice("平台%d 账号 %d 准备登录", agent.PlatformId, agent.Id)
			if u.loadLottery(agent) {
				logs.Notice("平台 %d 账号 %d 登录成功 ", agent.PlatformId, agent.Id)
			} else {
				logs.Notice("平台 %d 账号 %d 登录失败 ", agent.PlatformId, agent.Id)
			}
		} else {
			agent.SetLoginStatus(false)
			u.destroyAgent(agent)
		}
	}
}

func (u *UserProc) destroyAgent(agent *models.Agent) {
	if u.existsAgent(agent) {
		lottery, ok := u.getLottery(agent.Id, agent.PlatformId)
		if !ok {
			return
		}

		lottery.Destroy()
		u.delLottery(agent)
	}
}

func (u *UserProc) getAgentKey(agent *models.Agent) string {
	return fmt.Sprintf("%d_%d", agent.PlatformId, agent.Id)
}

func (u *UserProc) getLottery(agentId int64, platformId int) (lottery ILottery, ok bool) {
	u.mux.RLock()
	defer u.mux.RUnlock()
	platformLotterys, ok := u.lotterys[platformId]
	if !ok {
		return
	}

	lotteryCell, ok := platformLotterys[agentId]
	if ok {
		lottery = lotteryCell.Lottery
	}
	return
}

// 获取补单账号
// 现无补单账号区别
func (u *UserProc) getCompensatePlaceLottery(agentId int64, platformId int) (lottery ILottery, ok bool) {
	u.mux.RLock()
	defer u.mux.RUnlock()
	platformLotterys, ok := u.lotterys[platformId]
	if !ok {
		return
	}

	var lotteryCell *LotteryCell
	if agentId > 0 {
		lotteryCell, ok = platformLotterys[agentId]
		if ok && !lotteryCell.InUse && !lotteryCell.InSleep() {
			lotteryCell.Active()
			lottery = lotteryCell.Lottery
		} else {
			ok = false
		}
		return
	} else {
		for _, lotteryCell = range platformLotterys {
			// 随机取，不能取补水账号
			if lotteryCell.Lottery.AgentInfo().IsLogin && !lotteryCell.InUse && !lotteryCell.InSleep() && !lotteryCell.Prepare && lotteryCell.Lottery.AgentInfo().Type == 1 {
				ok = true
				lotteryCell.Active()
				lottery = lotteryCell.Lottery
				return
			}
		}
		ok = false
	}
	return
}

func (u *UserProc) getPlaceLottery(agentId int64, platformId int) (lottery ILottery, ok bool) {
	u.mux.RLock()
	defer u.mux.RUnlock()

	platformLotterys, exists := u.lotterys[platformId]
	if !exists {
		logs.Warn("平台%d 获取打水账号 %d 失败", platformId, agentId)
		return
	}

	var lotteryCell *LotteryCell
	if agentId > 0 {
		lotteryCell, exists := platformLotterys[agentId]
		if exists && !lotteryCell.InUse && !lotteryCell.InSleep() {
			ok = true
			lotteryCell.Active()
			lottery = lotteryCell.Lottery
			return
		}
	} else {
		for _, lotteryCell = range platformLotterys {
			if lotteryCell.Lottery.AgentInfo().IsLogin && !lotteryCell.InUse && !lotteryCell.InSleep() && !lotteryCell.Prepare {
				ok = true
				lotteryCell.Active()
				lottery = lotteryCell.Lottery
				return
			}
		}
	}
	logs.Warn("平台%d 获取打水账号 %d 失败", platformId, agentId)
	return
}

func (u *UserProc) putPlaceLotteryWithPrepare(lottery ILottery, prepare bool) {
	u.mux.Lock()
	defer u.mux.Unlock()
	platformLotterys, ok := u.lotterys[lottery.Platform()]
	if !ok {
		platformLotterys = make(map[int64]*LotteryCell)
		platformLotterys[lottery.AgentInfo().Id] = &LotteryCell{
			Lottery: lottery,
			Prepare: prepare,
		}
		u.lotterys[lottery.Platform()] = platformLotterys
		return
	} else {
		lotteryCell, ok := platformLotterys[lottery.AgentInfo().Id]
		if !ok {
			platformLotterys[lottery.AgentInfo().Id] = &LotteryCell{
				Lottery: lottery,
				Prepare: prepare,
			}
		} else {
			if prepare {
				lotteryCell.Prepare = prepare
				lotteryCell.InUse = false
			} else {
				lotteryCell.Sleep()
			}
		}
	}
	return
}

func (u *UserProc) setLotterySleep(agentId int64, platformId int) {
	if agentId == 0 {
		return
	}

	u.mux.Lock()
	defer u.mux.Unlock()
	if platformLotterys, ok := u.lotterys[platformId]; ok {
		lotteryCell, ok := platformLotterys[agentId]
		if ok {
			lotteryCell.Sleep()
		}
	}

}

func (u *UserProc) putPlaceLottery(lottery ILottery) {
	u.mux.Lock()
	defer u.mux.Unlock()
	platformLotterys, ok := u.lotterys[lottery.Platform()]
	if !ok {
		platformLotterys = make(map[int64]*LotteryCell)
		platformLotterys[lottery.AgentInfo().Id] = &LotteryCell{
			Lottery: lottery,
		}
		u.lotterys[lottery.Platform()] = platformLotterys
		return
	} else {
		lotteryCell, ok := platformLotterys[lottery.AgentInfo().Id]
		if !ok {
			platformLotterys[lottery.AgentInfo().Id] = &LotteryCell{
				Lottery: lottery,
			}
		} else {
			lotteryCell.Sleep()
		}
	}
	return
}

func (u *UserProc) setLottery(lottery ILottery) {
	u.mux.Lock()
	defer u.mux.Unlock()
	platformLotterys, ok := u.lotterys[lottery.Platform()]
	if !ok {
		platformLotterys = make(map[int64]*LotteryCell)
		platformLotterys[lottery.AgentInfo().Id] = &LotteryCell{
			Lottery: lottery,
		}
		u.lotterys[lottery.Platform()] = platformLotterys
		return
	} else {
		_, ok := platformLotterys[lottery.AgentInfo().Id]
		if !ok {
			platformLotterys[lottery.AgentInfo().Id] = &LotteryCell{
				Lottery: lottery,
			}
		}
	}

	return
}

func (u *UserProc) delLottery(agent *models.Agent) {
	u.mux.Lock()
	defer u.mux.Unlock()
	platformLotterys, ok := u.lotterys[agent.PlatformId]
	if !ok {
		return
	}
	delete(platformLotterys, agent.Id)
}

func (u *UserProc) existsAgent(agent *models.Agent) (ok bool) {
	u.mux.RLock()
	defer u.mux.RUnlock()
	platformLotterys, ok := u.lotterys[agent.PlatformId]
	if !ok {
		return
	}

	_, ok = platformLotterys[agent.Id]
	return
}

// 获取所有的代理账号
func (u *UserProc) getAgents() []*models.Agent {
	agents, err := models.GetUserAgents(u.user.Id)
	if err != nil {
		logs.Warn("get user %d agents err:%s", u.user.Id, err.Error())
		return nil
	}
	return agents
}

// 基础账号 水位获取
func (u *UserProc) loadLottery(agent *models.Agent) bool {
	if u.existsAgent(agent) {
		return true
	}

	agent.SetLoginStatus(false)
	lottery, ok := GetLottery(agent)
	if !ok {
		logs.Notice("平台%d 获取lottery失败，%+v", agent.PlatformId, agent)
		return ok // 初始化失败
	}

	logs.Notice("加载账号 %+v", agent)

	var loginResp *models.ActionResp
	for i := 0; i < 3; i++ {
		// 尝试登录三次
		loginResp = lottery.Login() // 登录
		if loginResp.IsSuccess {
			break
		}

		logs.Warn("平台 %d 账号 %d 登陆失败:%s", agent.PlatformId, agent.Id, loginResp.Msg)
	}

	if !loginResp.IsSuccess {
		return false
	}

	// 修改登录状态
	agent.SetLoginStatus(true)

	// 数据更新
	go lottery.Run()

	// 心跳监测
	go func(lottery ILottery) {
		tick := time.NewTicker(time.Second * 10)
		timeout := time.Minute * time.Duration(15+rand.Intn(20))
		ctx, cancel := context.WithTimeout(context.Background(), timeout)
		for _ = range tick.C {
			if lottery.IsStop() {
				cancel()
				return
			}

			select {
			case <-ctx.Done():
				logs.Notice("平台:%d 账号:%d 重新登录", lottery.Platform(), lottery.AgentInfo().Id)
				// 30分钟重新登录
				cancel()
				ctx, cancel = context.WithTimeout(context.Background(), timeout)
				agent.SetLoginStatus(false)
				actionResp := lottery.ReLogin()
				if actionResp.IsSuccess {
					agent.SetLoginStatus(true)
					logs.Notice("平台 %d 账号 %d 重新登录成功 ", lottery.Platform(), lottery.AgentInfo().Id)
				} else {
					logs.Warn("平台 %d 账号 %d 重新登录失败 %s", lottery.Platform(), lottery.AgentInfo().Id, actionResp.Msg)
				}
			default:
				// logs.Debug("=========== CheckLogin lottery %d  %d ", lottery.Platform(), agent.Id)
				if resp := lottery.CheckLogin(); !resp.IsSuccess {
					logs.Warn("CheckLogin 平台 %d 账号 %d =========== %s", lottery.Platform(), lottery.AgentInfo().Id, resp.Msg)
					logs.Notice("平台:%d 账号:%d 重新登录", lottery.Platform(), lottery.AgentInfo().Id)
					agent.SetLoginStatus(false)
					actionResp := lottery.ReLogin()
					if actionResp.IsSuccess {
						agent.SetLoginStatus(true)
						logs.Notice("平台 %d 账号 %d 重新登录成功 ", lottery.Platform(), lottery.AgentInfo().Id)
					} else {
						logs.Warn("平台 %d 账号 %d 重新登录失败 %s", lottery.Platform(), lottery.AgentInfo().Id, actionResp.Msg)
					}
				} else {
					if err := lottery.AgentInfo().UpdateBalance(); err != nil {
						logs.Warn("账号%d 更新余额失败:%s", lottery.AgentInfo().Id, err.Error())
					} else {
						logs.Notice("账号%d 更新余额成功，余额共%d分", lottery.AgentInfo().Id, lottery.AgentInfo().Balance)
					}

					if lottery.AgentInfo().Balance < 500000 {
						logs.Notice("账号余额过低，当前余额:%d,将暂停使用", lottery.AgentInfo().Balance)
						if err := lottery.AgentInfo().Pause(); err != nil {
							logs.Warn("暂停账号%d 失败:%s", lottery.AgentInfo().Id, err.Error())
						}

						lottery.Destroy()
					}
				}
			}
		}
	}(lottery)

	go func(agent *models.Agent, lottery ILottery) {
		for games := range lottery.GetGames() {
			logs.Debug("lottery %d agentId %d getGame %d", lottery.Platform(), lottery.AgentInfo().Id, len(games))
			u.saveGames(games, agent)
		}
	}(agent, lottery)

	go func(agent *models.Agent, lottery ILottery) {
		for gameDatas := range lottery.GetGameData() {
			logs.Debug("lottery %d agentId %d getGameData %d", lottery.Platform(), lottery.AgentInfo().Id, len(gameDatas))
			if len(gameDatas) == 0 {
				continue
			}

			offset := utils.CurrentMills() - gameDatas[0].CreateTime
			if offset > 5000 {
				logs.Debug("lottery %d agentId %d 数据超时:%d",
					lottery.Platform(), lottery.AgentInfo().Id, offset)
				continue
			}
			u.saveGameDatas(gameDatas, agent)
		}
	}(agent, lottery)

	u.putPlaceLottery(lottery)
	return ok
}
